﻿#include "mqttclient.h"
#include <QDebug>
#include <QHostAddress>

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>

// const QString DEFAULT_HOST = QString("192.168.1.1"); // 默认MQTT服务器地址
const QString DEFAULT_HOST = QString::fromUtf8("192.168.1.1"); // 推荐写法
// const QString DEFAULT_HOST = QString::fromUtf8("192.168.1.1"); // 推荐写法
const quint16 DEFAULT_PORT = 8883;
const quint16 DEFAULT_MQTT_PORT = 1883;

MqttClient::MqttClient(QObject *parent)
    : QObject(parent),
    _mqttClient(new QMQTTClient(QHostAddress())),
    _port(20006)
{
    // _mqttClient = new QMQTTClient(QHostAddress());
    // _mqttClient->setHostName(tr("127.0.0.1")); //broker.emqx.io"));
    // _mqttClient->setTopicSub(tr("/dev/thirdjam/command/passbacktarget"));
    // _mqttClient->setTopicPub(tr("/dev/thirdjam/command/passbacktarget"));

    QObject::connect(_mqttClient, &QMQTTClient::connected, this, &MqttClient::onConnected);
    QObject::connect(_mqttClient, &QMQTTClient::disconnected, this, &MqttClient::onDisconnected);
    // connect(_mqttClient, &QMQTT::Client::received, this, &MqttClient::onMessageReceived);
    QObject::connect(_mqttClient, &QMQTTClient::messageReceived, this, &MqttClient::readBytes);

    // 2. 定时器设置为3秒
    reconnectTimer = new QTimer(this);
    reconnectTimer->setInterval(3000);
    reconnectTimer->setSingleShot(false);
    // 3. 定时器每次触发都检查连接状态
    connect(reconnectTimer, &QTimer::timeout, this, &MqttClient::checkConnection);
    // 5. 开机自启自动连接
    reconnectTimer->start();
}

void MqttClient::checkConnection()
{
    // bool reconnecting = false;
    // auto state = _mqttClient->connectionState();
    // qDebug() << state;
    // switch (state) {
    // case QMQTT::STATE_INIT:
    //     qDebug() << "️STATE_INIT";
    //     reconnecting = true; // 允许重连
    //     break;
    // case QMQTT::STATE_CONNECTING:
    //     qDebug() << "STATE_CONNECTING";
    //     reconnecting = false; // 允许重连
    //     break;
    // case QMQTT::STATE_CONNECTED:
    //     reconnecting = false;
    //     qDebug() << "STATE_CONNECTED";
    //     break;
    // case QMQTT::STATE_DISCONNECTED:
    //     qDebug() << "STATE_DISCONNECTED";
    //     reconnecting = true; // 重连完成
    //     break;
    // }

    // if(reconnecting)  _mqttClient->connectToHost();

    //connectToHost();
    // qDebug() << "start connectToHost";
    // if (_mqttClient->isConnected() ) {
    //     connectToHost();
    // }else {
    //     _isConnected =true;

    // }

    // connectToHost();
    if (_mqttClient->isConnectedToHost()) {
        qDebug() << "Already connected.";
        return;
    }
    _mqttClient->connectToHost();

    // connectToHost();
}

void MqttClient::connectToHost(void) {


    if (_mqttClient->isConnectedToHost()) {
        qDebug() << "Already connected.";
        return;
    }

    /**
     * 每个连接的 MQTT 客户端都需要提供一个唯一的 Client ID，以区分不同的客户端。
     * 如果多个客户端使用相同的 Client ID，MQTT 代理会断开先前的连接，保留最新的客户端连接。
     */
    /*
    // 根据应用场景决定是否启用加上时间作为ClientId
    QTime current_time = QTime::currentTime();
    QString time = QString("%1:%2:%3").arg(current_time.hour(), 2)
                       .arg(current_time.minute(), 2)
                       .arg(current_time.second(), 2);
    _mqttClient->setClientId(_MqttConfig->deviceId()+"/APP/"+time);
    */
    _mqttClient->setClientId(deviceId());// + tr("/APP"));
    /**
     * 在setTopics() 接口中，自动设置 订阅与发布话题
     * 订阅话题: testtopic/MAV
     * 发布话题: testtopic/GCS
     * 代码会自动添加：
        /MAV后缀用于订阅（接收来自飞控的消息）
        /GCS后缀用于发布（发送消息到飞控）
     * 每个无人机有自己独立的消息通道，保持发布和订阅路径的对称性
     */



    // _mqttClient->setTopics(tr("testtopic123"));    // 设置MQTT主题（topic）的基础前缀
    // 区分不同设备或应用：可以是一个客户ID、设备ID或应用标识符，确保不同设备/用户的消息不会互相干扰

    _mqttClient->setAutoReconnectInterval(60);
    _mqttClient->setAutoReconnect(true);

    /**
     * EMQX 访问控制 - 客户端认证 - 用户创建的用户名与密码
     * https://cloud.emqx.com
     */
    bool isNeedUserAndPs = false;  // 有些 Mqtt服务器不需要用户名与密码，根据服务器设置调整此处代码
    if(isNeedUserAndPs) {
        _mqttClient->setUsername(tr("username"));
        _mqttClient->setPassword("password");
    }

    qDebug() << "_topicSub" << _mqttClient->_topicSub;
    qDebug() << "_topicPub" << _mqttClient->_topicPub;
    qDebug() << "host" << _mqttClient->host();
    qDebug() << "hostName" << _mqttClient->hostName();
    qDebug() << "port" << _mqttClient->port();

    _mqttClient->connectToHost();
}

void MqttClient::subscribeTopic(const QString &topic) {
    if (_mqttClient->isConnectedToHost()) {
        qDebug() << "Subscribe:" << topic;
        // _mqttClient->subscribe(topic);
        _mqttClient->setTopics(topic);    // 设置MQTT主题（topic）的基础前缀
    }
}

void MqttClient::publishMessage(const QString &msg) {
    if (_mqttClient->isConnectedToHost()) {
        _mqttClient->publishMsg(msg.toUtf8());
        qDebug() << "Publish:"  << msg;
    }
}

void MqttClient::publishMessage(const QString &topic, const QString &msg,
                                int qos, bool retain) {
    if (_mqttClient->isConnectedToHost()) {
        // QString realTopic = topic.isEmpty() ? _defaultTopic : topic;
        QString realTopic =  topic;
        if (realTopic.isEmpty()) {
            qWarning() << "Publish failed: topic is empty!";
            return;
        }

        QMQTT::Message message(0, realTopic, msg.toUtf8(), qos, retain);
        _mqttClient->publish(message);

        qDebug() << "Publish:" << realTopic << msg;
    } else {
        qWarning() << "Not connected to MQTT broker, cannot publish!";
    }
}

void MqttClient::onMessageReceived(QByteArray msg) {
}


// 工具函数：安全获取字符串
inline QString getString(const QJsonObject &obj, const QString &key, const QString &defaultValue = QString())
{
    if (!obj.contains(key) || obj.value(key).isNull())
        return defaultValue;

    const QJsonValue &val = obj.value(key);

    // 如果本身是字符串
    if (val.isString())
        return val.toString();

    // 如果是数字、布尔等类型，转 QVariant 再 toString
    return val.toVariant().toString();
}

//底层 QMQTTClient ==> MqttClient
void MqttClient::readBytes(const QString &topic, const QByteArray &msg) {
    _lastTopic   = topic;
    _lastMessage = QString::fromUtf8(msg);
    // qDebug() << "Message received: [" << _lastTopic << "] " << _lastMessage;

    // 尝试解析 JSON
    QJsonParseError parseError;
    QJsonDocument doc = QJsonDocument::fromJson(msg, &parseError);

    if (parseError.error != QJsonParseError::NoError) {
        qWarning() << "JSON parse error:" << parseError.errorString();
        emit messageChanged();
        return;
    }

    if (!doc.isObject()) {
        qWarning() << "Invalid JSON message (not an object)";
        emit messageChanged();
        return;
    }

    QJsonObject obj = doc.object();

    QString longitudeStr = getString(obj, QStringLiteral("longitude"));
    QString latitudeStr  = getString(obj, QStringLiteral("latitude"));
    QString altitudeStr  = getString(obj, QStringLiteral("altitude")); // 有些 JSON 没有，可以缺省

    // 转换为 double
    bool ok1, ok2, ok3;
    double lon = longitudeStr.toDouble(&ok1);
    double lat = latitudeStr.toDouble(&ok2);
    double alt = altitudeStr.toDouble(&ok3);

    if (!ok1 || !ok2) {
        qWarning() << "Invalid lon/lat:" << longitudeStr << latitudeStr;
        emit messageChanged();
        return;
    }

    // 转换为整数：经纬度 * 1e7，高度转厘米
    qint64 lonInt = static_cast<qint64>(lon * 1e7);
    qint64 latInt = static_cast<qint64>(lat * 1e7);
    qint64 altInt = ok3 ? static_cast<qint64>(alt * 100.0) : 0;

    QString forwardMsg = QString(tr("$TGT,%1,%2,%3\n"))
                             .arg(lonInt)
                             .arg(latInt)
                             .arg(altInt);

    // qDebug() << "Forward to serial:" << forwardMsg;

    // emit messageChanged();
    emit messageReceived(_lastTopic, msg);           // 给 AppController 转发用

    // 👇 如果 AppController 开启了转发，可以调用串口发送
    emit forwardPrepared(forwardMsg.toUtf8());

    // // 提取字段
    // QString deviceId       = getString(obj, QStringLiteral("deviceId"));
    // QString time           = getString(obj, QStringLiteral("time"));
    // QString router         = getString(obj, QStringLiteral("router"));
    // QString targetId       = getString(obj, QStringLiteral("targetId"));
    // QString SOG            = getString(obj, QStringLiteral("SOG"));
    // QString COG            = getString(obj, QStringLiteral("COG"));      // 可能没有，返回空串
    // QString targetType     = getString(obj, QStringLiteral("targetType"));
    // QString UTCTimestamp   = getString(obj, QStringLiteral("UTCTimestamp"));
    // QString freqPoint      = getString(obj, QStringLiteral("freqPoint"));
    // QString missileId      = getString(obj, QStringLiteral("missileId")); // int 或 string 都能处理
    // QString targetDistance = getString(obj, QStringLiteral("targetDistance"));

    // // 打印调试
    // qDebug() << "  deviceId:"       << deviceId;
    // qDebug() << "  time:"           << time;
    // qDebug() << "  router:"         << router;
    // qDebug() << "  targetId:"       << targetId;
    // qDebug() << "  longitude:"      << longitudeStr;
    // qDebug() << "  latitude:"       << latitudeStr;
    // qDebug() << "  altitude:"       << altitudeStr;
    // qDebug() << "  SOG:"            << SOG;
    // qDebug() << "  COG:"            << COG;
    // qDebug() << "  targetType:"     << targetType;
    // qDebug() << "  UTCTimestamp:"   << UTCTimestamp;
    // qDebug() << "  freqPoint:"      << freqPoint;
    // qDebug() << "  missileId:"      << missileId;
    // qDebug() << "  targetDistance:" << targetDistance;



    // if (mqttForward && serial.connected()) {
    //     QString line = QString("%1,%2,%3")
    //     .arg(_lastTopic)
    //         .arg(_latitude)
    //         .arg(_longitude); // 以后可加 altitude
    //     serial.sendData(line);
    // }
}

//连接槽函数
void MqttClient::onConnected()
{
    qDebug() << "Connected to MQTT broker.";
    emit connectedChanged();
}

void MqttClient::onDisconnected()
{
    qDebug() << "Disconnected from MQTT broker.";
    emit connectedChanged();
}

void MqttClient::disconnectFromHost()
{
    if (_mqttClient->isConnectedToHost()) {
        _mqttClient->disconnectFromHost();
    }
}

void MqttClient::setHost(const QString &host)
{
    _host = host;
    QHostAddress address;
    if (address.setAddress(host)) {
        // 说明 host 是 IP 地址
        _mqttClient->setHost(address);
    } else {
        // 说明 host 是域名（QHostAddress 不支持域名）
        // 用 setHostname() 而不是 setHost()
        _mqttClient->setHostName(host);
    }
    qDebug() << "host:" << host;
}

void MqttClient::setPort(int port)
{
    _port = port;
    _mqttClient->setPort(_port);
}

//构造函数之后的 UI 初始化
void MqttClient::setSubTopic(const QString &topic) {


    if (_subTopic != topic) {
        _subTopic = topic;
        _mqttClient->setTopicSub(tr("/dev/thirdjam/command/passbacktarget"));
        emit subTopicChanged();
    }
}
